/** @file
	@brief Definitions related to #PrynEditorPath.

	This file relates to autorouting of pin connections on the editor board. The entry point is #PrynEditorPath, which contains a grid of #PrynEditorPathIntersection that refer to the join of two #PrynEditorPathLine. Pin connections use #PrynEditorPathRoute to describe the route to take, which is a collection of #PrynEditorPathStep indicating which intersections to move through.

	This entire file is generally of no use to the client, as the route's internally maintained. As such, there is no C++ interface for it, and it is not normally exported for use by other languages.
	*/
#ifndef PRYN_EDITOR_PATH_H
#define PRYN_EDITOR_PATH_H

#include <pryn/platform.h>

typedef struct PrynEditorPathLine PrynEditorPathLine; ///< A horizontal or vertical line in the path.
typedef struct PrynEditorPathIntersection PrynEditorPathIntersection; ///< An intersection of horizontal and vertical lines.
typedef struct PrynEditorPath PrynEditorPath; ///< A grid of data describing a layout of components and routes.
typedef struct PrynEditorPathStep PrynEditorPathStep; ///< A step on a route.
typedef struct PrynEditorPathRoute PrynEditorPathRoute; ///< A route from one position to another on the grid.
typedef PrynDList (PrynEditorPathIntersection) PrynEditorPathIntersectionList; ///< Linked list of intersections.

#include <pryn/gui/control.h>
#include <pryn/gui/painter.h>

/// Invalid score to indicate that an intersection is not on the path.
#define PrynEditorPathScoreInvalid 0

/// A step in a route.
struct PrynEditorPathStep
{
	PrynEditorPathIntersection *intersection; ///< Intersection to use.
	bool vertical; ///< Whether this step is vertical.
};

/// A computed route.
struct PrynEditorPathRoute
{
	PrynEditorPath *path; ///< Path this route is on.
	PrynEditorPathStep *steps; ///< List of steps.
	size_t count; ///< Number of steps.
	int sx; ///< Starting horizontal coordinate of the route.
	int sy; ///< Starting vertical coordinate of the route.
	int ex; ///< Ending horizontal coordinate of the route.
	int ey; ///< Ending vertical coordinate of the route.
};

/// A horizontal or vertical line in the path.
struct PrynEditorPathLine
{
	int offset; ///< The offset from the origin of this line.
	bool collapsable; ///< Allow collapsing into a nearby line if this flag is set. Even if false they can still collapse if they overlap.
};

/// An intersection on the path.
struct PrynEditorPathIntersection
{
	PrynEditorPathIntersection *next; ///< Next element in the set or 0 if this is last.
	PrynEditorPathIntersection *previous; ///< Previous element in the set or 0 if this is first.
	
	size_t horizontal; ///< Horizontal line index.
	size_t vertical; ///< Vertical line index.
	PrynEditorPathIntersection *up; ///< Intersection in the up direction (y-), or zero for none.
	PrynEditorPathIntersection *down; ///< Intersection in the down direction (y+), or zero for none.
	PrynEditorPathIntersection *left; ///< Intersection in the left direction (x-), or zero for none.
	PrynEditorPathIntersection *right; ///< Intersection in the right direction (x+), or zero for none.
	
	PrynEditorPathIntersection *last; ///< Last intersection in the best score, or 0 if this has no score yet.
	size_t estimate; ///< Estimated score from this intersection to the target.
	size_t score; ///< Best score at this intersection, or PrynEditorPathScoreInvalid if it's not on the path.
	bool closed; ///< Whether this is in the closed set.
	bool opened; ///< Whether this is in the opened set.
};

/// A path. This is a grid on top of the board on which connection routes can be searched for.
struct PrynEditorPath
{
	PrynEditorPathLine *horizontals; ///< Horizontal lines.
	size_t horizontalCount; ///< Number of horizontal lines.
	size_t horizontalAllocated; ///< Allocated number of horizontal lines.
	
	PrynEditorPathLine *verticals; ///< Vertical lines.
	size_t verticalCount; ///< Number of vertical lines.
	size_t verticalAllocated; ///< Allocated number of vertical lines.
	
	PrynEditorPathIntersection *intersections; ///< Intersections between horizontal and vertical lines.
	size_t intersectionCount; ///< Number of intersections.
	size_t intersectionAllocated; ///< Allocated number of intersections.
	
	PrynEditorPathIntersectionList open; ///< Open set.
	PrynEditorPathIntersectionList closed; ///< Closed set.
};

PrynEditorImport (void, prynEditorPathDestroy, (PrynState *state, PrynEditorPath *path))
	/**< @brief Free all data in the path.

	@param state The state object.
	@param path The path to clear out. This does not free the path itself. */

PrynEditorImport (PrynResult, prynEditorPathSetup, (PrynEditorBoard *board, PrynEditorPath *path))
	/**< @brief Initialise path with all the components in the board.

	@param board The board to search.
	@param path The path grid to update. Before the first call to this function, path must be cleared to zeroes. Subsequent calls reuse the path as much as possible. 
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorPathPaintLattice, (PrynEditorPath *path, PrynGuiPainter *painter))
	/**< @brief Paint the intersections of the path and connecting lines between them.

	This is used for debugging; it's not normally visible.

	@param path The path grid to use as a data source.
	@param painter The painter to render to. The brush and pen will be overwritten.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (PrynEditorPathIntersection *, prynEditorPathIntersectionAt, (PrynEditorPath *path, size_t horizontal, size_t vertical))
	/**< @brief Return the intersection at a given point.

	@param path The path grid the intersection is contained in.
	@param horizontal The zero-based horizontal index of the intersection.
	@param vertical The zero-based vertical index of the intersection.
	@returns The intersection or 0 on failure. */

PrynEditorImport (PrynEditorPathIntersection *, prynEditorPathFindClosestIntersection, (PrynEditorPath *path, int x, int y, bool down))
	/**< @brief Find the closest intersection to the given point.
	
	This will search to the left of and below (if @e down is true) or above (if @e down is false) the point on the board.

	@param path The path grid to search.
	@param x The absolute horizontal position to start the search at. The matching intersection will be at most this position.
	@param y The absolute vertical position to start the search at. The matching intersection will be at most this position if @e down is true, or at least this position if @e down is false.
	@param down Whether to search for an intersection above (true) or below (false) the @e y reference point.
	@returns The intersection or 0 on failure. */

PrynEditorImport (int, prynEditorPathIntersectionX, (PrynEditorPath *path, PrynEditorPathIntersection *intersection))
	/**< @brief Return the X coordinate of the intersection.

	@param path The path grid the intersection is within.
	@param intersection The intersection to get the position of.
	@returns The absolute horizontal offset of the intersection, or 0 if there was a problem. */

PrynEditorImport (int, prynEditorPathIntersectionY, (PrynEditorPath *path, PrynEditorPathIntersection *intersection))
	/**< @brief Return the Y coordinate of the intersection.

	@param path The path grid the intersection is within.
	@param intersection The intersection to get the position of.
	@returns The absolute vertical offset of the intersection, or 0 if there was a problem. */

PrynEditorImport (PrynResult, prynEditorPathComputeRoute, (PrynState *state, PrynEditorPath *path, int sx, int sy, int ex, int ey, PrynEditorPathRoute *route))
	/**< @brief Compute a route.
	
	This route usually won't include the start and end points, but if you complete an elbow as (sx, sy), (sx, first point y), (first point x, first point y), and the same for the end, then it will attach properly. The elbow isn't necessary if you start from a connected pin because the pin establishes a vertical line. Instead, just draw a line from the starting and ending position to the first and last points.

	@param state The state to use for allocations.
	@param[in, out] path The path grid information. If a route is found, intersections will be written to to prevent their reuse by other routes.
	@param sx The starting horizontal coordinate of the path to calculate.
	@param sy The starting vertical coordinate of the path to calculate.
	@param ex The ending horizontal coordinate of the path to calculate.
	@param ey The ending vertical coordinate of the path to calculate.
	@param[out] route The route to write. Any data on the route will be modified.
	@returns #PrynResultSuccess if a route was found, #PrynResultDone if not. An unfound path will be rendered by #prynEditorPathPaintRoute as a straight line from start to end. This may also return an error; see #PrynResult. */

PrynEditorImport (void, prynEditorPathDestroyRoute, (PrynState *state, PrynEditorPathRoute *route))
	/**< @brief Delete all data in a route.

	@param state The state that was used to allocate the route information.
	@param route The route to destroy. It will be cleared to all zeroes. */

PrynEditorImport (PrynResult, prynEditorPathPaintRoute, (PrynEditorPathRoute *route, PrynGuiPainter *painter))
	/**< @brief Paint the route using a line.

	@param route The route to paint. If this is zeroed, nothing is painted. If this is an empty route (containing starting and ending points but no intermediate) then it's rendered as a straight line. Otherwise a circuitous line is made through each intersection and the starting and ending points.
	@param painter The painter to use. The current brush will be used for drawing the line.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorPathRouteDirty, (PrynEditorPathRoute *route, PrynGuiControl *control))
	/**< @brief Dirty the areas that the path runs through.

	@param route The route to dirty. This will dirty everything that would be touched if #prynEditorPathPaintRoute were to be called.
	@param control The control to dirty areas on.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

#endif /* PRYN_EDITOR_PATH_H */
